﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.DirectoryServices;
    using System.Diagnostics;
    using System.Threading; 
    #endregion

    /// <summary>
    /// When querying for an ExchangeServer, the base DN should be: CN=Microsoft Exchange,CN=Services,[configuration naming context DN]
    /// </summary>
    [Serializable]
    public class ExchangeServer : ADBaseObjectProperties {

        #region Members
        public string AdminDisplayName { get; private set; }

        public bool IsExchange2003 {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 6.5", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2003RTM {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 6.5 (Build 6944", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2003SP2 {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 6.5 (Build 7638", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2010 {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 14.", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2010RTM {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 14.0.639", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2010SP1 {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 14.1", StringComparison.OrdinalIgnoreCase));
            }
        }

        public bool IsExchange2010SP2 {
            get {
                return this.SerialNumber.Any(x => x.StartsWith("Version 14.2", StringComparison.OrdinalIgnoreCase));
            }
        }

        public string LegacyExchangeDN { get; private set; }

        public bool MessageTrackingEnabled { get; private set; }

        public MSExchCurrentServerRoles MSExchCurrentServerRoles { get { return msExchCurrentServerRoles; } }
        private MSExchCurrentServerRoles msExchCurrentServerRoles;

        public MSExchVersion MSExchVersion { get { return msExchVersion; }  }
        private MSExchVersion msExchVersion;

        public static readonly string ObjectCategoryShortName = "msExchExchangeServer";

        /// <summary>
        /// Exchange 2003 = Version 6.5...
        /// Exchange 2010 SP1 = Version 14.1...
        /// </summary>
        public IReadOnlyList<string> SerialNumber { get; private set; }
        #endregion

        #region Constructor
        public ExchangeServer() {
            this.Initialize();
        } 

        public ExchangeServer(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
                if (this.GetType().Name == typeof(ExchangeServer).Name) {
                this.Attributes = null;
            }
        }

        public ExchangeServer(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
                if (this.GetType().Name == typeof(ExchangeServer).Name) {
                this.Attributes = null;
            }
        }

        public ExchangeServer(List<string> ldifOutput)
            : base(ldifOutput) {
                if (this.GetType().Name == typeof(ExchangeServer).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            base.Initialize();

            this.AdminDisplayName = string.Empty;
            this.LegacyExchangeDN = string.Empty;
            msExchCurrentServerRoles = MSExchCurrentServerRoles.Undefined;
            msExchVersion = MSExchVersion.Undefined;
            this.SerialNumber = new List<string>();
        }
        protected override void ProcessResults() {

            try {
                base.ProcessResults();

                if (this.Attributes.ContainsKey("adminDisplayName")) {
                    this.AdminDisplayName = this.Attributes["adminDisplayName"][0].ToString();
                }
                if (this.Attributes.ContainsKey("legacyExchangeDN")) {
                    this.LegacyExchangeDN = this.Attributes["legacyExchangeDN"][0].ToString();
                }
                if (this.Attributes.ContainsKey("messageTrackingEnabled")) {
                    this.MessageTrackingEnabled = Convert.ToBoolean(this.Attributes["messageTrackingEnabled"][0]);
                }
                if (this.Attributes.ContainsKey("msExchCurrentServerRoles")) {
                    Enum.TryParse<MSExchCurrentServerRoles>(
                        this.Attributes["msExchCurrentServerRoles"][0].ToString(), ignoreCase: true, result: out msExchCurrentServerRoles);
                }
                if (this.Attributes.ContainsKey("msExchVersion")) {
                    Enum.TryParse<MSExchVersion>(
                        this.Attributes["msExchVersion"][0].ToString(), ignoreCase: true, result: out msExchVersion);
                }
                this.SerialNumber = ADDataAccess.GetMultiValuedAttribute<string>("serialNumber", this.Attributes);

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN)
                    && this.ObjectClass.Any(x => string.Equals(x, ObjectCategoryShortName, StringComparison.OrdinalIgnoreCase));            
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }
        } 
        #endregion

    }
}
